<template>
  <div v-loading.fullscreen="isLoadingFull">
    <el-form ref="formDom" :model="form" label-width="auto" status-icon>
      <template v-for="(item, index) in formData">
        <el-form-item
          :key="index"
          class="formItem"
          v-if="(item.type!='editor' && !item.hasOwnProperty('showRule')) || (item.type!='editor' && item.showRule.includes(formShow))"
          :label="item.label"
          :rules="item.rules"
          :prop="item.prop"
          size="large"
        >
          <el-input
            v-if="item.type === 'input'"
            v-model="form[item.prop]"
            autocomplete="off"
            :placeholder="item.placeholder"
            :style="{ width: item.width }"
          />
          <el-input
            v-else-if="item.type === 'password'"
            type="password"
            autocomplete="new-password"
            v-model="form[item.prop]"
            :placeholder="item.placeholder"
            :style="{ width: item.width }"
          />
          <el-input
            v-else-if="item.type === 'textarea'"
            type="textarea"
            v-model="form[item.prop]"
            :placeholder="item.placeholder"
            :style="{ width: item.width }"
          />
          <el-select
            v-else-if="item.type === 'select'"
            v-model="form[item.prop]"
            :multiple="item.setAttr.multiple"
            :placeholder="item.placeholder"
            :style="{ width: item.width }"
          >
            <el-option
              v-for="(option, i) in item.options"
              :key="i"
              :label="option[item.setAttr.label]"
              :value="option[item.setAttr.value]"
            />
          </el-select>
          <el-cascader
            v-else-if="item.type === 'cascader'"
            v-model="form[item.prop]"
            :options="item.options"
            :props="item.props"
            :placeholder="item.placeholder"
            :style="{ width: item.width }"
          />
          <el-tree-select
            v-else-if="item.type === 'threeSelect'"
            v-model="form[item.prop]"
            :data="item.options"
            :node-key="item.nodeKey"
            :render-after-expand="false"
            :placeholder="item.placeholder"
            :style="{ width: item.width }"
            :props="item.props"
            :check-strictly="true"
          />
          <template v-else-if="item.type === 'checkbox'">
            <div v-if="!item.options.length">加载中，请稍候</div>
            <el-checkbox-group v-model="form[item.prop]">
              <el-checkbox
                style="margin-bottom: 15px"
                v-for="(o, i) in item.options"
                :value="o[item.setAttr.value]"
                border
                >{{ o[item.setAttr.label] }}</el-checkbox
              >
            </el-checkbox-group>
          </template>
          <el-radio-group
            v-else-if="item.type === 'radio'"
            v-model="form[item.prop]"
            @change="item.change"
          >
            <el-radio
              v-for="(o, i) in item.options"
              :key="i"
              :value="o.value"
              size="large"
              border
              >{{ o.label }}</el-radio
            >
          </el-radio-group>

          <el-input-number v-else-if="item.type === 'number'" v-model="form[item.prop]" />
          <el-switch
            v-else-if="item.type === 'switch'"
            v-model="form[item.prop]"
            :active-value="item.options.activeValue"
            :inactive-value="item.options.inactiveValue"
          />
          <!-- check-strictly -->
          <el-tree
            v-else-if="item.type === 'tree'"
            class="formItem_tree"
            ref="treeItemRef"
            :style="{ width: item.width }"
            :props="item.props"
            :data="item.options"
            :node-key="item.nodeKey"
            :default-checked-keys="item.default"
            check-strictly
            empty-text="加载中，请稍候"
            highlight-current
            show-checkbox
          />
          <Upload
            v-else-if="item.type === 'file'"
            @uploadSuccessCallback="(res) => uploadSuccessCallback(res, item.prop)"
            :imageUrl="form[item.prop]"
            :preview="item.options.preview"
            :cropper="item.options.cropper"
            :multiple="item.options.multiple"
            :limit="item.options.limit"
            :category="item.options.category"
          ></Upload>
          <div v-else-if="item.type === 'icon'">
            <el-input
              v-model="form[item.prop]"
              autocomplete="off"
              :placeholder="item.placeholder"
              :style="{ width: item.width }"
              style="margin-bottom: 10px"
              readonly
            >
              <template #prepend v-if="form[item.prop]">
                <el-icon>
                  <component :is="form[item.prop]"></component>
                </el-icon>
              </template>
            </el-input>
            <IconSelect
              :choiceThis="form[item.prop]"
              @choiceIcon="
                (val) => {
                  form[item.prop] = val;
                }
              "
            ></IconSelect>
          </div>
        </el-form-item>
        <Editor v-if="item.type === 'editor'" ref="editorRef" :value="form[item.prop]"></Editor>
      </template>
    </el-form>
    <div class="form-footer">
      <el-button type="primary" color="#626aef" round @click="submitForm(formDom)">提交</el-button>
      <el-button type="info" round @click="resetForm(formDom)">重置</el-button>
    </div>
    <div style="height: 100px"></div>
  </div>
</template>

<script setup name="Form">
import { encrypt, decrypt } from "@/utils/jsencrypt";
import Upload from "@/components/Upload";
import IconSelect from "@/components/IconSelect";
import Editor from "@/components/Editor";
import { watch } from "vue";
/**
 * apiUrl 接口地址
 * formShow 表单显示状态-用于动态显示配合showRule
 * formData：{
 *  label: 表单标题
 *  prop: 表单属性
 *  type: 表单类型
 *    input: input框
 *    cascader: 级联选择框
 *    threeSelect: 三级联动选择框
 *    radio: 单选框
 *    number: 数字输入框
 *    switch: 开关
 *  rules: 表单验证规则
 *  placeholder: 表单提示信息
 *  width: 表单宽度
 *  options: 表单选项
 *  nodeKey: 表单threeSelect树形结构节点key
 *  props: 表单树形结构属性
 *  change: 表单树形结构change事件
 *  showRule: 表单显示规则
 * }
 */
const props = defineProps({
  apiUrl: { type: Object, default: {} },
  formData: { type: Array, default: [] },
  formShow: { type: String, default: "1" },
});
const formDom = ref();
const treeItemRef = ref();
const editorRef = ref();
const form = ref({});
// submitReset 提交后触发
const emit = defineEmits(["submitReset"]);
const { proxy } = getCurrentInstance();
const isLoadingFull = ref(false);

watch(
  () => props.formShow,
  (newVal, oldVal) => {
    if (newVal != oldVal) {
      let newForm = {};
      props.formData.forEach((item) => {
        if (!item.hasOwnProperty("showRule") || item.showRule.includes(props.formShow)) {
          newForm[item.prop] = form.value.hasOwnProperty(item.prop)
            ? form.value[item.prop]
            : item.default;
        }
      });
      if (form.value.hasOwnProperty("id")) newForm.id = form.value.id;
      form.value = newForm;
    }
  }
);

const initFormData = (formData) => {
  form.value = formData;
};

defineExpose({ initFormData });
const setData = () => {
  let tData = props.formData.filter((item) => {
    return item.type === "tree" || item.type === "editor";
  });
  if (tData.length && tData[0].type==="tree") {
    let checked = treeItemRef.value[0].getCheckedKeys(false);
    let checkedPid = treeItemRef.value[0].getHalfCheckedKeys();
    form.value[tData[0].prop] = [...checkedPid, ...checked];
  }
   if (tData.length && tData[0].type==="editor") {
    form.value[tData[0].prop] = editorRef.value[0].getVal();
  }
  if (form.value.hasOwnProperty("oPassword") && form.value.oPassword) {
    form.value.oPassword = encrypt(form.value.oPassword);
  }
  if (form.value.hasOwnProperty("password") && form.value.password) {
    form.value.password = encrypt(form.value.password);
  }
};
const submitForm = async (formEl) => {
  if (!formEl) return;
  await formEl.validate(async (valid, fields) => {
    if (valid) {
      isLoadingFull.value = true;
      //设置form 特殊数据 password tree
      setData();
      if (form.value.hasOwnProperty("id")) {
        formEdit();
      } else {
        formAdd();
      }
    } else {
    }
  });
};

const formAdd = () => {
  props.apiUrl
    .add(form.value)
    .then((res) => {
      if (res.code === 200) {
        resetForm(formDom.value);
        emit("submitReset");
        proxy.$notify({
          title: "提交成功，刷新页面中...",
          type: "success",
        });
      }
    })
    .finally(() => {
      isLoadingFull.value = false;
    });
};

const formEdit = () => {
  props.apiUrl
    .edit(form.value)
    .then((res) => {
      if (res.code === 200) {
        proxy.$notify({
          title: "修改成功，刷新页面中...",
          message: "编号为" + form.value.id + "的数据修改成功",
          type: "success",
        });
        resetForm(formDom.value);
        emit("submitReset");
      }
    })
    .finally(() => {
      isLoadingFull.value = false;
    });
};

const resetForm = (formEl) => {
  if (!formEl) return;
  formEl.resetFields();
};

const uploadData = reactive({
  imageUrl: "",
});
const uploadSuccessCallback = (url, field) => {
  form.value[field] = url;
};
</script>

<style lang="scss">
.form-footer {
  @include posBox(absolute, null, 0, null, 0, 99);
  @include flexBox(row, flex-end, center);
  width: 100%;
  padding: 20px;
  overflow: hidden;
  background: var(--page-background);

  .el-button.is-round {
    flex-shrink: 0;
    border-radius: 25px;
    padding: 22px 0px;
    width: 155px;
    font-size: 16px;
  }
}
.formItem {
  &_tree {
    border: var(--el-border);
    padding: 5px 0;
    border-radius: var(--el-border-radius-base);
    .el-tree-node {
      padding: 5px 0;
    }
  }
}
</style>
